//AbstractComputeFX
//Created 28/06/16
//Created By Daniel Bowler
//
//AbstractFX will work happily for the CS effects, but somethings are not needed
//(Eg the input layout), so I figured it would be best to have a seperate class.

#pragma once

#include <d3dx11.h>
#include "d3dx11Effect.h"
#include "d3dUtil.h"

#include <string>
#include <vector>

//Typedefs to make things easier - optional. 
typedef struct ID3DX11EffectTechnique Technique;
typedef struct ID3DX11Effect Effect;
typedef struct ID3D11InputLayout InputLayout;
typedef struct ID3DX11EffectPass Pass;
typedef struct _D3DX11_PASS_DESC PassDescription;
typedef struct _D3DX11_TECHNIQUE_DESC TechniqueDescription;
typedef struct _D3DX11_EFFECT_DESC EffectDescription;

//Typedef the effect variables aswell
typedef struct ID3DX11EffectVariable EffectRawVariable; //Our custom data that requires raw data transfer.
typedef struct ID3DX11EffectMatrixVariable EffectMatrixVariable;
typedef struct ID3DX11EffectVectorVariable EffectVectorVariable;
typedef struct ID3DX11EffectShaderResourceVariable EffectShaderResourceVariable; //Eg, texture maps
typedef struct ID3DX11EffectScalarVariable EffectScalarVariable; //Eg floats
typedef struct ID3DX11EffectUnorderedAccessVariable UnorderedAccessVariable;
typedef struct ID3DX11EffectUnorderedAccessViewVariable UnorderedAccessViewVariable;

//Forward declare ShaderManager so that all the subclasses are aware of it
//when they need to declare the ShaderManager as a friend.
class ShaderManager;

class AbstractComputeFX
{

public:
	//Structure to hold data for each technique in a given effect (file)
	struct TechniqueData
	{
		TechniqueData()
		{
			tech = NULL;
			noOfPasses = 0;
			passDescArray = NULL;
		}
		~TechniqueData()
		{	
			delete []passDescArray;
			passDescArray = NULL;
		}

		//Technique pointer
		ID3DX11EffectTechnique* tech;
		//Technique description structure
		D3DX11_TECHNIQUE_DESC techDesc;
		//Technique name.
		LPCSTR techniqueName;
		//Unsigned integer holding the numebr of passes
		//for this technique.
		unsigned noOfPasses;
		//A pass description struct - one per pass (Its an example of a dynamically
		//created array). 
		D3DX11_PASS_DESC* passDescArray;
	};

public:
	//Returns the effect pointer. 
	ID3DX11Effect* ReturnEffect(){return effect;};
	//Effect description - useful if you need to access
	//the number of techniques in this effect
	D3DX11_EFFECT_DESC ReturnEffectDesc(){return effectDesc;};
	//Returns the current active technique data structure.
	TechniqueData* ReturnActiveTechniqueData(){return activeTechniqueData;};
	//Returns individual components of the active TechniqueData struct
	ID3DX11EffectTechnique* ReturnActiveTechnique(){return activeTechniqueData->tech;};
	D3DX11_TECHNIQUE_DESC   ReturnActiveTechniqueDesc(){return activeTechniqueData->techDesc;};
	LPCSTR					ReturnActiveTechniqueName(){return activeTechniqueData->techniqueName;};
	//Use the next two functions together (eg: D3DX11_PASS_DESC* d = shader->ReturnActive...PassDescArray())
	//										   d[shader->ReturnActive....NumberOfPasses()].....
	//To access data for a specific pass. 
	unsigned				ReturnActiveTechniqueNumberOfPasses(){return activeTechniqueData->noOfPasses;};
	D3DX11_PASS_DESC*       ReturnActiveTechniquePassDescArray(){return activeTechniqueData->passDescArray;};
	ID3DX11EffectPass*		ReturnActiveTechniquePassPointer(unsigned index);

	//Function that applies the active technique for a given pass.
	void ApplyActiveTechniqueForPass(unsigned p, ID3D11DeviceContext* context);

public:
	//Functions to set the current active technique
	void SetActiveTechniqueByName(LPCSTR techniqueName);
	void SetActiveTechniqueByIndex(unsigned index);

protected:
	//We will call the constructor explicitly in our subclasses via an initilisation
	//list. 
	AbstractComputeFX(ID3D11Device* device, const std::wstring& filename);
	//Abstract class will handle Releasing the effect and inputLayout pointers.
	virtual ~AbstractComputeFX() = 0;

	//Override this function - and call them in the subclasses constructor
	//to correctly init a shader.
	virtual void InitShaderVariablePointers() = 0;

protected:
	//Effect pointers and related things that all effects/shaders share. 
	//Our effect pointer. 
	ID3DX11Effect* effect;
	//Effect description
	D3DX11_EFFECT_DESC effectDesc;

	//Techniques - We will have a vector of TechniqueData structs. Each representing
	//a single technique and the x number of passes they hold. 
	std::vector<TechniqueData*>techniqueArray;
	//Active technique data (our custom structure). I have provided getter functions
	//to return this pointer aswell as the data inside the struct. 
	TechniqueData* activeTechniqueData;

private:
	//Disable copy constructor and assignment operator.
	AbstractComputeFX(const AbstractComputeFX& other);
	AbstractComputeFX& operator = (const AbstractComputeFX& other);
};